package com.google.code.greenplate;

import android.app.Activity;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.SystemClock;
import android.provider.Settings;
import android.util.Log;

public class GPSListener implements LocationListener {

	private static final String TAG = "GPSListener";

	private int lat = 0;
	private int lng = 0;
	private static final double MILLION = 1000000.0;

	LocationManager lm = null;
	// Request 0.5 seconds between updates
	private static final int LOCATION_UPDATE_INTERVAL_MILLIS = 500;
	// Request update if greater than 1000m change
	private static final float LOCATION_DISTANCE_INTERVAL_METERS = 1000.0f;

	// Don't use the network location unless it has been at least this
	// much time since we got a location from the GPS
	private static final long RETAIN_GPS_MILLIS = 5000L;
	// Time in millis for the last time GPS reported a location
	private long lastGPSFixTime = 0L;

	// Set to true when it has location for this instance of GPSListener
	private boolean hasLocation = false;

	Activity activity;

	// Initialize with the activity to store global variables
	public GPSListener(final Activity callingActivity) {
		this.activity = callingActivity;
	}

	// Check if this device has network location capabilities
	public boolean getGPSStatus() {
		String allowedLocationProviders = Settings.System.getString(activity
				.getContentResolver(),
				Settings.System.LOCATION_PROVIDERS_ALLOWED);
		if (allowedLocationProviders == null)
			allowedLocationProviders = "";
		return allowedLocationProviders.contains(LocationManager.GPS_PROVIDER);
	}

	// Check if this device has network location capabilities
	public boolean getNetworkStatus() {
		String allowedLocationProviders = Settings.System.getString(activity
				.getContentResolver(),
				Settings.System.LOCATION_PROVIDERS_ALLOWED);
		if (allowedLocationProviders == null)
			allowedLocationProviders = "";
		return allowedLocationProviders
				.contains(LocationManager.NETWORK_PROVIDER);
	}

	// Register for location updates
	public void getLocation() {
		lm = (LocationManager) activity
				.getSystemService(Context.LOCATION_SERVICE);

		if (getNetworkStatus()) {
			lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
					LOCATION_UPDATE_INTERVAL_MILLIS,
					LOCATION_DISTANCE_INTERVAL_METERS, this);
		}

		if (getGPSStatus()) {
			lm.requestLocationUpdates(LocationManager.GPS_PROVIDER,
					LOCATION_UPDATE_INTERVAL_MILLIS,
					LOCATION_DISTANCE_INTERVAL_METERS, this);
		}

		// Start counting how old the GPS signal is
		lastGPSFixTime = SystemClock.uptimeMillis();
	}

	// Unregister for location updates
	public void pauseLocation() {
		lm.removeUpdates(this);
	}

	// Callback when a location provider has a new locaton to report
	public void onLocationChanged(Location location) {

		// double check
		if (location == null) {
			return;
		}

		final long now = SystemClock.uptimeMillis();
		boolean useLocation = false;
		final String provider = location.getProvider();
		if (LocationManager.GPS_PROVIDER.equals(provider)) {
			Log.d(TAG, "Location found by GPS");

			// Use GPS if available
			lastGPSFixTime = SystemClock.uptimeMillis();
			useLocation = true;
		} else if (LocationManager.NETWORK_PROVIDER.equals(provider)) {
			Log.d(TAG, "Location found by Network");

			// Use network provider if GPS is getting stale
			useLocation = ((now - lastGPSFixTime) > RETAIN_GPS_MILLIS);
			lastGPSFixTime = SystemClock.uptimeMillis();
			lastGPSFixTime = 0L;
		}
		if (useLocation) {
			lat = (int) (location.getLatitude() * MILLION);
			lng = (int) (location.getLongitude() * MILLION);

			Log.d(TAG, "Location found: Altitude = " + location.getAltitude());

			hasLocation = true;
		}
	}

	// /////////////////////////////////////////////////////////////////////////////
	// Methods to allow the parent to retrieve location info from GPSListener
	public boolean foundLocation() {
		return (hasLocation);
	}

	public int getLat() {
		return (lat);
	}

	public int getLng() {
		return (lng);
	}

	// /////////////////////////////////////////////////////////////////////////////

	public void onProviderDisabled(String provider) {
	}

	public void onProviderEnabled(String provider) {
	}

	// One of the registered location providers has changed its availability
	public void onStatusChanged(String provider, int status, Bundle extras) {
	}

}